package de.zainodis.triplog.data.sync;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
import android.os.Bundle;
import android.util.Log;

import junit.framework.Assert;

import org.json.JSONException;

import de.zainodis.triplog.R;
import de.zainodis.triplog.data.DataProvider;
import de.zainodis.triplog.data.JsonParser;
import de.zainodis.triplog.data.LocationEntry;
import de.zainodis.triplog.data.TripEntry;

/**
 * Responsible for syncing data with the server.
 * Created by fzarrai on 8/30/2014.
 */
public class TriplogSyncAdapter extends AbstractThreadedSyncAdapter {
    private static final String TAG = "TriplogSyncAdapter";
    public static final String ACTION_WEATHER_SYNC_COMPLETE = "WeatherSyncComplete";

    /**
     * Pass via bundle, if not specified, default is 10 days.
     */
    public static final String BUNDLE_FORECAST_DAYS = "ForecastDays";


    public TriplogSyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
    }

    @Override
    public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
        //We always request the data in metric system and convert it if needed
        String unit = getContext().getString(R.string.pref_value_metric);
        String numberOfDays = String.valueOf(extras.getInt(BUNDLE_FORECAST_DAYS, 10));

        //Get current Location
        TripEntry trip = DataProvider.getCurrentTrip();
        if (trip == null) {
            trip = TripEntry.queryForOpen(getContext(), false);
        }
        LocationEntry location = trip.getLocation();

        Assert.assertNotNull("Location must be specified!", location);
        Log.i(TAG, "Starting sync.");

        String result = JsonParser.requestWeatherForecast(location.getLocationSetting(), unit, numberOfDays);
        if (result == null) {
            return;
        }
        try {
            //Persists the weather data to the database
            new JsonParser().storeWeatherDataFromJson(getContext(), result, location);

            Intent intent = new Intent();
            intent.setAction(ACTION_WEATHER_SYNC_COMPLETE);
            getContext().sendBroadcast(intent);
        } catch (JSONException e) {
            Log.e(TAG, "JSON parse exception during onPerformSync.", e);
        }
    }


    /**
     * Helper method to have the sync adapter sync immediately
     *
     * @param context The context used to access the account service
     */
    public static void syncImmediately(Context context, String location, int numberOfDays) {
        Bundle bundle = new Bundle();
        bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
        bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
        bundle.putInt(BUNDLE_FORECAST_DAYS, numberOfDays);
        ContentResolver.requestSync(getSyncAccount(context),
                context.getString(R.string.content_authority), bundle);
    }

    /**
     * Helper method to get the fake account to be used with SyncAdapter, or make a new one
     * if the fake account doesn't exist yet. If we make a new account, we call the
     * onAccountCreated method so we can initialize things.
     *
     * @param context The context used to access the account service
     * @return a fake account.
     */
    public static Account getSyncAccount(Context context) {
        // Get an instance of the Android account manager
        AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);

        // Create the account type and default account
        Account newAccount = new Account(context.getString(R.string.app_name), context.getString(R.string.sync_account_type));

        // If the password doesn't exist, the account doesn't exist
        if (null == accountManager.getPassword(newAccount)) {

            /*
            * Add the account and account type, no password or user data
            * If successful, return the Account object, otherwise report an error.
            */
            if (!accountManager.addAccountExplicitly(newAccount, "", null)) {
                return null;
            }
            /*
            * If you don't set android:syncable="true" in
            * in your <provider> element in the manifest,
            * then call ContentResolver.setIsSyncable(account, AUTHORITY, 1)
            * here.
            */
        }
        return newAccount;
    }

}
